# -*- coding: utf8 -*-
from fraction import Fraction
from lat_lon_parser import parse
import numpy as np



geosot_grid_size_latitude_list = [None,2*3600,30*60,15*60,1*60,4,2,1/4,1/32,1/256,1/2048]
geosot_grid_size_circle_inner_longitude_list = [None,360*3600,120*3600,120*3600,24*3600,24*3600,90*3600,45*3600,45*3600,45*3600,45*3600]
geosot_grid_size_longitude_list = [None,360*3600,60*3600,30*3600,24*3600,24/15*3600,24/15/15*3600,24/15/15/2*3600,24/15/15/2/8*3600,24/15/15/2/8/8*3600,24/15/15/2/8/8/8*3600]
geosot_grid_count_longitude_list = [None,1,2,2,15,15,2,8,8,8,8]


digital_str = '0123456789ABCDEF'



def beidou_grid_encoding_bit_1_4(latitude):
    lat = parse(latitude)
    if lat > 0:
        code = 'N000'
    elif lat < 0:
        code = 'S000'
    else:
        raise Exception('latitude argument may be error,please check')
    return code


def beidou_grid_encoding_bit_5_6(longitude,latitude):
    level_n = 2
    latitude_size = geosot_grid_size_latitude_list[level_n]/3600
    if latitude >= 90 - latitude_size:
        code = '00'
    elif 90 - 2 * latitude_size <= latitude < 90 - latitude_size:
        if 0 <= longitude < 120:
            code = '01'
        elif 120 <= longitude < 240:
            code = '02'
        else:
            code = '03'
    else:
        # latitude_range = [88,90 - 2 * latitude_size]  #[88,89)
        longitude_size_level_n_1 = geosot_grid_size_longitude_list[level_n-1]/3600
        code_bit_5 = np.floor(longitude / longitude_size_level_n_1) + 1
        # compute sixth bit
        longitude_size = geosot_grid_size_longitude_list[2]/3600
        base_point_long = longitude_size_level_n_1 * (code_bit_5 - 1)
        long_code = np.floor((longitude - base_point_long)/longitude_size)
        base_point_lat = 88
        lat_code = np.floor((latitude - base_point_lat)/latitude_size)
        long_grid_count = geosot_grid_size_longitude_list[level_n-1]/geosot_grid_size_longitude_list[level_n]
        if code_bit_5 < 3:
            code_bit_6 = lat_code * long_grid_count + long_code
        else:
            code_bit_6 = lat_code * long_grid_count + (long_grid_count -1 - long_code)
        code = '{}{}'.format(int(code_bit_5),int(code_bit_6))
    return code


def beidou_grid_encoding_bit_7(longitude,latitude):
    level_n = 3
    latitude_grid_size_level_n_1 = geosot_grid_size_latitude_list[level_n-1] / 3600
    latitude_grid_size_level_n = geosot_grid_size_latitude_list[level_n] / 3600
    longitude_grid_size_level_n_1 = geosot_grid_size_longitude_list[level_n - 1] / 3600
    longitude_grid_size_level_n = geosot_grid_size_longitude_list[level_n] / 3600
    position_long = np.floor(longitude / geosot_grid_size_longitude_list[1]) + 1

    if latitude >= 90 - latitude_grid_size_level_n_1:
        if latitude >= 90 - latitude_grid_size_level_n:
            code = 0
        else:
            code = np.floor(longitude/geosot_grid_size_longitude_list[1])+1
    elif 90 - 2 * latitude_grid_size_level_n_1 <= latitude <= 90 - latitude_grid_size_level_n_1:
        # 少一层，切的是二级网格形式
        longitude_grid_size_level_1 = geosot_grid_size_longitude_list[1] / 3600
        longitude_grid_size_level_2 = geosot_grid_size_longitude_list[2] / 3600
        latitude_grid_size_level_1 = geosot_grid_size_latitude_list[1] / 3600
        latitude_grid_size_level_2 = geosot_grid_size_latitude_list[2] / 3600
        base_point_long = np.floor(longitude / longitude_grid_size_level_1) * longitude_grid_size_level_1
        long_code = np.floor((longitude - base_point_long) / longitude_grid_size_level_2)
        base_point_lat = np.floor(latitude / latitude_grid_size_level_1) * latitude_grid_size_level_1
        lat_code = np.floor((latitude - base_point_lat) / latitude_grid_size_level_2)
        long_grid_count = longitude_grid_size_level_2 / longitude_grid_size_level_1
        if position_long < 3:
            code = lat_code * long_grid_count + long_code
        else:
            code = lat_code * long_grid_count + (long_grid_count - 1 - long_code)
    else:
        # latitude_range [88,89)
        base_point_long = np.floor(longitude/longitude_grid_size_level_n_1)*longitude_grid_size_level_n_1
        long_code = np.floor((longitude - base_point_long) / longitude_grid_size_level_n)
        # latitude code
        base_point_lat = np.floor(latitude/latitude_grid_size_level_n_1)*latitude_grid_size_level_n_1
        lat_code = np.floor((latitude - base_point_lat) / latitude_grid_size_level_n)
        long_grid_count = longitude_grid_size_level_n / longitude_grid_size_level_n_1
        if position_long < 3:
            code = lat_code * long_grid_count + long_code
        else:
            code = lat_code * long_grid_count + (long_grid_count - 1 - long_code)
    return str(code)



def beidou_grid_encoding_bit_8_9(longitude,latitude):
    level_n = 4
    latitude_grid_size_level_n_1 = geosot_grid_size_latitude_list[level_n-1] / 3600
    latitude_grid_size_level_n = geosot_grid_size_latitude_list[level_n] / 3600
    longitude_grid_size_level_n_1 = geosot_grid_size_longitude_list[level_n - 1] / 3600
    longitude_grid_size_level_n = geosot_grid_size_longitude_list[level_n] / 3600
    position_long = np.floor(longitude / geosot_grid_size_longitude_list[1]) + 1
    if latitude >= 90 - latitude_grid_size_level_n_1:
        if latitude >= 90 - latitude_grid_size_level_n:
            code = 0
        else:
            code = np.floor(longitude/geosot_grid_size_longitude_list[1])+1
    elif 90 - 2 * latitude_grid_size_level_n_1 <= latitude <= 90 - latitude_grid_size_level_n_1:
        # 少一层，切的是二级网格形式
        longitude_grid_size_level_1 = geosot_grid_size_longitude_list[1] / 3600
        longitude_grid_size_level_2 = geosot_grid_size_longitude_list[2] / 3600
        latitude_grid_size_level_1 = geosot_grid_size_latitude_list[1] / 3600
        latitude_grid_size_level_2 = geosot_grid_size_latitude_list[2] / 3600
        base_point_long = np.floor(longitude / longitude_grid_size_level_1) * longitude_grid_size_level_1
        long_code = np.floor((longitude - base_point_long) / longitude_grid_size_level_2)
        base_point_lat = np.floor(latitude / latitude_grid_size_level_1) * latitude_grid_size_level_1
        lat_code = np.floor((latitude - base_point_lat) / latitude_grid_size_level_2)
        long_grid_count = longitude_grid_size_level_2 / longitude_grid_size_level_1
        if position_long < 3:
            code = lat_code * long_grid_count + long_code
        else:
            code = lat_code * long_grid_count + (long_grid_count - 1 - long_code)
    else:
        # latitude_range [88,89)
        base_point_long = np.floor(longitude/longitude_grid_size_level_n_1)*longitude_grid_size_level_n_1
        long_code = np.floor((longitude - base_point_long) / longitude_grid_size_level_n)
        # latitude code
        base_point_lat = np.floor(latitude/latitude_grid_size_level_n_1)*latitude_grid_size_level_n_1
        lat_code = np.floor((latitude - base_point_lat) / latitude_grid_size_level_n)
        long_grid_count = longitude_grid_size_level_n / longitude_grid_size_level_n_1
        if position_long < 3:
            code = lat_code * long_grid_count + long_code
        else:
            code = lat_code * long_grid_count + (long_grid_count - 1 - long_code)
    return str(code)



def beidou_grid_encoding_bit_general(longitude,latitude,level_n):
    if level_n == 1:
        return 'N000'
    # level_n >= 2
    # 维度方向
    latitude_grid_size_level_n_1 = geosot_grid_size_latitude_list[level_n-1] / 3600
    latitude_grid_size_level_n = geosot_grid_size_latitude_list[level_n] / 3600
    # 经度方向
    # inner_longitude_grid_size_level_n_1 = geosot_grid_size_circle_inner_longitude_list[level_n - 1] / 3600
    inner_longitude_grid_size_level_n = geosot_grid_size_circle_inner_longitude_list[level_n] / 3600
    longitude_grid_size_level_n_1 = geosot_grid_size_longitude_list[level_n - 1] / 3600
    longitude_grid_size_level_n = geosot_grid_size_longitude_list[level_n] / 3600
    # 极点处的划分
    if latitude >= 90 - latitude_grid_size_level_n_1:
        if latitude >= 90 - latitude_grid_size_level_n:
            code = 0
        else:
            code = np.floor(longitude/inner_longitude_grid_size_level_n)+1

        code_int = int(code)
        if level_n == 2:
            code_str = '0{}'.format(code_int)
        elif level_n == 3:
            code_str = '{}'.format(code_int)
        elif level_n == 4:
            code_str = '{}0'.format(digital_str[code_int])
        elif level_n == 5:
            code_str = '{}0'.format(digital_str[code_int])
        elif level_n == 6:
            code_str = '{}'.format(code_int)
        else:
            code_str = '{}0'.format(digital_str[code_int])
    # elif 90 - 2 * latitude_grid_size_level_n_1 <= latitude <= 90 - latitude_grid_size_level_n_1:
    else:
        base_point_lat = np.floor((latitude - 88)/latitude_grid_size_level_n_1) * latitude_grid_size_level_n_1 + 88
        lat_position = int(np.floor((latitude - base_point_lat)/inner_longitude_grid_size_level_n))
        base_point_long = np.floor(longitude/longitude_grid_size_level_n_1) * longitude_grid_size_level_n_1
        long_position = int(np.floor((longitude-base_point_long)/longitude_grid_size_level_n))
        # 所在区域 东经，西经
        position_section_long = int(np.floor(longitude / geosot_grid_size_longitude_list[1]) + 1)
        if level_n == 2:
            if position_section_long < 3:
                code_bit_6 = lat_position * geosot_grid_count_longitude_list[level_n] + long_position
            else:
                code_bit_6 = lat_position * geosot_grid_count_longitude_list[level_n] + (geosot_grid_count_longitude_list[level_n] - 1 - long_position)
            code_str = '{}{}'.format(int(position_section_long), int(code_bit_6))
        elif (level_n == 3) or (level_n == 6):
            if position_section_long < 3:
                code_bit_6 = lat_position * geosot_grid_count_longitude_list[level_n] + long_position
            else:
                code_bit_6 = lat_position * geosot_grid_count_longitude_list[level_n] + (geosot_grid_count_longitude_list[level_n] - 1 - long_position)
            code_str = '{}'.format(digital_str[int(code_bit_6)])
        else:
            if position_section_long < 3:
                code_str = '{}{}'.format(digital_str[long_position],digital_str[lat_position])
            else:
                code_str = '{}{}'.format(digital_str[geosot_grid_count_longitude_list[level_n]+1-long_position], digital_str[lat_position])
    return code_str



def beidou_grid_encoding(longitude,latitude,level_n):
    # 格式化经纬度表示
    long_std = parse(longitude)
    lat_std = parse(latitude)
    long_std_abs = long_std if long_std >= 0 else long_std + 360
    lat_std_abs = np.abs(lat_std)
    code_str_list = [beidou_grid_encoding_bit_general(long_std_abs,lat_std_abs,i) for i in range(1,level_n+1,1)]
    return ''.join(code_str_list)




if __name__ == '__main__':
    # 经度 - x 轴
    longitude = 'E116°18′45.37″'
    # 维度 - y 轴
    latitude = 'N89°59′35.38″'
    for i in range(1, 11, 1):
        result_level_n = beidou_grid_encoding(longitude,latitude,i)
        print('level i -{}- result is'.format(i), result_level_n)
